package org.myspringframework.core;

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author Bob
 */
public class ClassPathXmlApplicationContext implements ApplicationContext {


    private final Map<String, Object> beanMap = new HashMap<>();

    public ClassPathXmlApplicationContext(String resource) {
        //解析 filePath ，也就是解析 xml 的文件，提出 bean 标签，创建对象，并保存到 singletonObjects 中
        try {
            InputStream is = this.getClass().getClassLoader().getResourceAsStream(resource);
            if (is == null) {
                System.err.println("无法加载资源文件: " + resource);
            } else {
                System.out.println("成功加载资源文件");
            }
            // 打印文件内容（调试）
            String xmlContent = new BufferedReader(new InputStreamReader(is))
                    .lines().collect(Collectors.joining("\n"));
            System.out.println("XML 文件内容:\n" + xmlContent);

            SAXReader reader = new SAXReader();
            // 重新读取（因为上面已经消费了 InputStream）
            is = this.getClass().getClassLoader().getResourceAsStream(resource);
            Document document = reader.read(is);

            // 4. 检查解析结果
            Element root = document.getRootElement();
            System.out.println("🌳 根节点: " + root.getName());

            List<Node> beanNodes = document.selectNodes("//bean");
            System.out.println("🔍 找到的 bean 数量: " + beanNodes.size());
            //实例化
            beanNodes.forEach(beanNode -> {
                Element beanElt = (Element) beanNode;
                // 获取id
                String id = beanElt.attributeValue("id");
                // 获取className
                String className = beanElt.attributeValue("class");
                try {
                    // 通过反射机制创建对象
                    Class<?> clazz = Class.forName(className);
                    Constructor<?> defaultConstructor = clazz.getDeclaredConstructor();
                    Object bean = defaultConstructor.newInstance();
                    // 存储到Map集合
                    beanMap.put(id, bean);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });
            beanNodes.forEach(this::setProperties);
        } catch (Exception e) {
            e.printStackTrace();
        }


    }

    public void setProperties(Node beanNode){
        Element beanElt = (Element) beanNode;
        // 获取id
        String id = beanElt.attributeValue("id");
        List<Element> elements = beanElt.elements();
        try {
            Class<?> clazz =  beanMap.get(id).getClass();
            elements.forEach(propertyNode -> {
                try {
                    String propertyName = propertyNode.attributeValue("name");
                    //获取属性类型
                    Class<?> type = clazz.getDeclaredField(propertyName).getType();
                    //获取set方法名
                    String setterMethodName = "set" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1);
                    //获取set方法
                    Method setterMethod = clazz.getDeclaredMethod(setterMethodName, type);
                    //属性值可能是 value 也可能是 ref
                    String propertyValue = propertyNode.attributeValue("value");
                    String propertyRef = propertyNode.attributeValue("ref");

                    // 如果属性值是 value，则通过辨别是哪种类型，然后进行赋值
                    Object propertyVal = null;
                    if(propertyValue != null){
                        propertyVal = switch (type.getSimpleName()) {
                            case "byte", "Byte" -> Byte.valueOf(propertyValue);
                            case "short", "Short" -> Short.valueOf(propertyValue);
                            case "int", "Integer" -> Integer.valueOf(propertyValue);
                            case "long", "Long" -> Long.valueOf(propertyValue);
                            case "float", "Float" -> Float.valueOf(propertyValue);
                            case "double", "Double" -> Double.valueOf(propertyValue);
                            case "boolean", "Boolean" -> Boolean.valueOf(propertyValue);
                            case "char", "Character" -> propertyValue.charAt(0);
                            case "String" -> propertyValue;
                            default -> propertyVal;
                        };
                        setterMethod.invoke( beanMap.get(id), propertyVal);
                    }
                    if(propertyRef != null){
                        propertyVal = beanMap.get(propertyRef);
                        setterMethod.invoke( beanMap.get(id), propertyVal);
                    }

                } catch (Exception e) {
                    throw new RuntimeException(e);
                }

            });
        } catch (Exception e) {
            throw new RuntimeException(e);
        }


    }
    @Override
    public Object getBean(String beanId) {
        return beanMap.get(beanId);
    }
}
